using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Apache.Cassandra;
using Cassandraemon.Serialization;


namespace Cassandraemon
{


	static class MappingUtil
	{
		
		public static List<Column> MappingColumn(object obj)
		{
			var columns = CassandraSerializer.ToColumns(obj);
			return columns;
		}
		
		public static T MappingObject<T>(List<Column> columns)
		{
			if(IsValueTypeOrString(typeof(T)))
			{
				return MappingUtil.MappingValueType<T>(columns);
			}
			
			T item = CassandraSerializer.ToObject<T>(columns);
			return item;
		}
		
		public static T MappingValueType<T>(List<Column> columns)
		{
			if(columns == null) return default(T);
			if(columns.Count() == 0) return default(T);
			
			return MappingValueType<T>(columns[0].Value);
		}
		
		public static T MappingValueType<T>(byte[] item)
		{
			return (T)MappingValueType(typeof(T), item);
		}
		
		public static object MappingValueType(Type type, byte[] item)
		{
            if (type.IsEnum)
            {
                return item.ToEnum(type);
            }
            var typeCode = Type.GetTypeCode(type);
            switch (typeCode)
            {
                case TypeCode.Boolean:
                    return item.ToBool();
                case TypeCode.Byte:
                    return item.ToByte();
                case TypeCode.Char:
                    return item.ToChar();
                case TypeCode.DBNull:
                    break;
                case TypeCode.DateTime:
                    return item.ToDateTime();
                case TypeCode.Decimal:
                    break;
                case TypeCode.Double:
                    return item.ToDouble();
                case TypeCode.Empty:
                    break;
                case TypeCode.Int16:
                    return item.ToInt16();
                case TypeCode.Int32:
                    return item.ToInt32();
                case TypeCode.Int64:
                    return item.ToInt64();
                case TypeCode.Object:
                    break;
                case TypeCode.SByte:
                    return item.ToSByte();
                case TypeCode.Single:
                    return item.ToSingle();
                case TypeCode.String:
                    return item.ToUTF8();
                case TypeCode.UInt16:
                    return item.ToUInt16();
                case TypeCode.UInt32:
                    return item.ToUInt32();
                case TypeCode.UInt64:
                    return item.ToUInt64();
                default:
                    break;
            }
			if(type.Equals(typeof(byte[])))
			{
				return item;
			}
			else if(type.Equals(typeof(sbyte[])))
			{
				return item.Cast<sbyte>().ToArray();
			}
			else if(type.Equals(typeof(TimeSpan)))
			{
				return item.ToTimeSpan();
			}
			else if(type.Equals(typeof(Guid)))
	        {
				return item.ToGuid();
			}
			else if(type.Name == "Nullable`1")
			{
				return MappingValueType(type.GetGenericArguments()[0], item);
			}
			else
			{
				return item.ToObject(type);
			}
		}	
		
		public static bool IsValueTypeOrString(Type type)
		{
			return type.IsValueType || type.Equals(typeof(string)) ? true : false;
		}
	}
}
